package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.common.BaseContext;
import com.itheima.reggie.common.CustomException;
import com.itheima.reggie.entity.*;
import com.itheima.reggie.mapper.OrderMapper;
import com.itheima.reggie.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author 程达
 * @PackageName:com.itheima.reggie.service.impl
 * @ClassName:OrderServiceImpl
 * @Description:
 * A. 获得当前用户id, 查询当前用户的购物车数据
 * B. 根据地址ID, 查询地址数据
 * C. 组装订单明细数据, 计算订单总价值，批量保存订单明细
 * D. 组装订单数据（订单Id ,日期、状态、价值、订单编号等）, 保存订单数据
 * E. 删除当前用户的购物车列表数据
 **/

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {

    // 订单详情  service
    @Autowired
    private OrderDetailService orderDetailService;
    // 购物项 service
    @Autowired
    private ShoppingCartService shoppingCartService;
    //地址簿  service
    @Autowired
    private AddressBookService addressBookService;
    //用户表 service
    @Autowired
    private UserService userService;

    @Override
    @Transactional
    public void submit(Orders orders) {
        log.info("进行提交订单:"+orders);
        log.info("先把需要别的表的数据 查询出来");
        // 基于 刚才分析  先查出来 当前用户的id
        Long userId = BaseContext.getCurrentId();
        // 基于 当前用户id ---购物车数据
        LambdaQueryWrapper<ShoppingCart> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(ShoppingCart::getUserId,userId);
        // 查询出所有的购物项
        List<ShoppingCart> shoppingCarts = shoppingCartService.list(wrapper1);
        // 基于 地址id查询 地址簿信息
        //地址id
        Long addressBookId = orders.getAddressBookId();
        AddressBook addressBook = addressBookService.getById(addressBookId);
        // 基于 用户id查询用户名
        User user = userService.getById(userId);

        // orders只有 三个字段.....  基于仨字段和当前登录用户
        // 1:   生成订单号  // 50位 随机的这种
        //通过 mp的一个类中的一个方法
        long orderId = IdWorker.getId();//通过mp生成一个 不重复id  默认雪花算法
        orders.setNumber(orderId+"");//这个订单id可以是32UUID 可以是19雪花算法id
        //  2:  下单用户的id---登录人就是下单人 BaseContext.getCurrentId()
        orders.setUserId(userId);
        //  3:  下单的时候 地址id 被封装到 orders里面了
        //  4:   下单时间---当前时间
        orders.setOrderTime(LocalDateTime.now());
        //  5:   结账时间--暂时先写当前时间 后期进行结账在更新
        orders.setCheckoutTime(LocalDateTime.now());
        // 7:    remark--已经封装到 orders里面了
        // 8:    phone--address---consignee  ---地址表里面  根据地址簿表查询
        orders.setPhone(addressBook.getPhone());
        orders.setAddress(addressBook.getDetail());
        orders.setConsignee(addressBook.getConsignee());
        // 9:    user_name 用户名  --- 用户表里面查  根据用户id查询
        orders.setUserName(user.getName());

        //  6:   amount--实际收取的总金额---需要遍历每个购物项 累加
        //为保证我们每一次执行的累加计算是一个原子操作，我们这里用到了JDK中提供的一个原子类 AtomicInteger
        //  总金额  //累加变量保证数据的准确性，并发工具类，保证数据原子性  原子性、可见性和有序性。
        //  CAS 即比较并替换，实现并发算法时常用到的一种技术（ABA）
        AtomicInteger amount = new AtomicInteger(0);
        //  10:  该订单对应的 订单明细....
        //  除了 订单id  内容全来自购物项  所有只要有该用户购物车 就可以封装
        // 订单项是多个
        List<OrderDetail> orderDetails = new ArrayList<>();
        //遍历 购物项
        for (ShoppingCart shoppingCart : shoppingCarts) {
            // shoppingCart ---每一个购物项
            //  orderDetail---每一个订单明细
            OrderDetail orderDetail = new OrderDetail();
            // 每个订单项中需要 name image dish_id setmeal_id dish_flavor  number amount
            // 都在自 购物项
            // 订单详情的属性 要拷贝自 购物项
            BeanUtils.copyProperties(shoppingCart,orderDetail,"orderId");
            // 再把订单id 塞进去
            orderDetail.setOrderId(orderId);
            //orderDeltail 存到集合中
            orderDetails.add(orderDetail);
            // ===============算账的 ==========
            //   一个菜品的单价
            BigDecimal danjia = orderDetail.getAmount();
            //   这个菜品的数量
            int number = orderDetail.getNumber();
            //  danjia*number  这是一个购物项的总价
            BigDecimal fenshu = new BigDecimal(number+"");
            // 单价成份数  每个购物项的价格
            // danjia.multiply(fenshu);//这个就是每个购物项的价格
            // 循环过程中 多个购物项的价格 要累加 给 外面定义的  总价格
            //是Java中的内置方法，该方法将在函数的参数中传递的值添加到先前的值，并返回数据类型为定义类型的新更新值。相当于  sum +=
            amount.addAndGet((danjia.multiply(fenshu)).intValue());// 相当于  sum +=  这是新知识点
            // 我们把钱 定义为元....intValue 变成整数，不要小数点后面的
            //因为我们 单位是在分上 所有用整型 自动完成 取 元的后两位  分后面就省略了

        }
        // 添加总价格
        orders.setAmount(new BigDecimal(amount.get()));
        // 总价 转换成 int
        // int转换回 bigDecimal

        // 是不是订单数据封装完了  orders
        //保存订单数据
        this.save(orders);
        //是不是 订单明细封装完了  orderDetails
        orderDetailService.saveBatch(orderDetails);
        // 是不是购物项没用了
        shoppingCartService.remove(wrapper1);//根据用户id删除

    }
}